#include "ines.h"
#include "util.h"

#include <gtk/gtk.h>

static GtkWidget *drawingArea;
static volatile bool exitGameLoop;

static uint8 pixels[PPU_VIDEO_HEIGHT * PPU_VIDEO_WIDTH * 3];

static void ines_game_callback(const uint8 *pixelBuf) {
    for (int i = 0; i < PPU_VIDEO_HEIGHT; ++i) {
        uint32 offset = i * PPU_VIDEO_WIDTH;
        for (int j = 0; j < PPU_VIDEO_WIDTH; ++j) {
            uint8 idx = pixelBuf[offset + j] & 0x3F;
            const uint8 *pixel = DEF_PPU_PALETTE[idx];
            uint32 k = (offset + j) * 3;
            pixels[k] = pixel[0];
            pixels[k + 1] = pixel[1];
            pixels[k + 2] = pixel[2];
        }
    }
    gtk_widget_queue_draw(drawingArea);
}

static gpointer ines_game_loop(gpointer *userData) {
    uint8 *buffer = ines_fread_all("../../rom/ines.nes", NULL);
    NesConsole *console = ines_console_new(buffer, (InesGameCallback) ines_game_callback);
    g_object_ref(drawingArea);
    exitGameLoop = False;
    while (!exitGameLoop) {
        uint32 cycle = ines_console_execute(console);
    }
    //Dispose NesConsole instance
    ines_console_dispose(&console);
    g_object_unref(drawingArea);
}

static void drawing_area_func(GtkDrawingArea *drawing_area,
                              cairo_t *cr,
                              int width,
                              int height,
                              gpointer user_data) {

    GdkRectangle rectangle = {0, 0, 256, 240};
    gdk_cairo_rectangle(cr, &rectangle);

    GBytes *bytes = g_bytes_new(pixels, PPU_VIDEO_HEIGHT * PPU_VIDEO_WIDTH * 3);
    GdkPixbuf *pixBuf = gdk_pixbuf_new_from_bytes(bytes, GDK_COLORSPACE_RGB, FALSE, 8, PPU_VIDEO_WIDTH,
                                                  PPU_VIDEO_HEIGHT, PPU_VIDEO_WIDTH * 3);
    gdk_cairo_set_source_pixbuf(cr, pixBuf, 0, 0);
    cairo_fill(cr);
    g_bytes_unref(bytes);
    g_object_unref(pixBuf);
}

static void gtk_activate(GtkApplication *app, gpointer userData) {
    drawingArea = gtk_drawing_area_new();
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "gines");
    gtk_window_set_default_size(GTK_WINDOW(window), 256, 240);
    gtk_window_set_child(GTK_WINDOW(window), drawingArea);
    gtk_window_present(GTK_WINDOW(window));
    gtk_widget_set_visible(drawingArea, TRUE);
    gtk_widget_set_size_request(drawingArea, 256, 240);
    gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawingArea), drawing_area_func, NULL, NULL);

    g_thread_new("ines_game_thread", (GThreadFunc) ines_game_loop, NULL);

}

static void gtk_shutdown(GApplication *app, gpointer userData) {
    exitGameLoop = TRUE;
}

int main(int argc, String *argv) {
    GtkApplication *app = gtk_application_new("cn.navclub.gines", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(gtk_activate), NULL);
    g_signal_connect(app, "shutdown", G_CALLBACK(gtk_shutdown), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}